package cn.b.sky.shop.activiti.controller;

import cn.b.sky.shop.activiti.model.NodeDTO;
import cn.b.sky.shop.activiti.model.condition.ProcessDefinitionCondition;
import cn.b.sky.shop.activiti.service.impl.EvunProcessEngine;
import cn.b.sky.shop.activiti.utils.CustomProcessDiagramGenerator;
import cn.b.sky.common.constants.SystemConstant;
import cn.b.sky.common.model.DWZResult;
import cn.b.sky.user.SecurityContextUtil;
import cn.b.sky.user.controller.SecurityController;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.ManagementService;
import org.activiti.engine.impl.cmd.GetBpmnModelCmd;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipInputStream;

/**
 * 
 * <strong>Title : ProcessEngineController<br></strong>
 * <strong>Package : cn.b.sky.shop.activiti.controller<br></strong>
 * <strong>Description : </strong> 流程引擎控制器，提供流程引擎发布，查询功能<br> 
 * <strong>Create on : 2014-10-6上午10:22:07<br></strong>
 * <p>
 * <strong>Copyright (c) 2014</strong>
 * <p>
 * @author lidapeng<br>
 * @version <strong>v1.0.0</strong><br>
 * <br>
 * <strong>修改历史:</strong><br>
 * 修改人  | 修改日期  | 修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 */
@Controller
@RequestMapping("/engine/*")
public class ProcessEngineController extends SecurityController {

  private static final Logger LOGGER= LoggerFactory.getLogger(ProcessEngineController.class);

  @Resource
  private EvunProcessEngine evunProcessEngine;

  @Resource
  private ManagementService managementService;

  @RequestMapping("deployengine")
  public String toDeployEngine(Model model) {

    return "engine/deploy";
  }

  /**
   * 
   * <strong>Title : deploy<br></strong>
   * <strong>Description : </strong>流程发布<br> 
   * <strong>Create on : 2014-10-6上午10:23:04<br></strong>
   * <p>
   * @param activitifile
   * @param request
   * @param model
   * @return DWZResult
   * @throws 
   * @author lidapeng<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人  | 修改日期  | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  @RequestMapping({ "deploy" })
  @ResponseBody
  public DWZResult deploy(@RequestParam("activitifile") MultipartFile activitifile, HttpServletRequest request,
                          Model model) {
    if (activitifile.isEmpty()) {
      return ajaxError(getImeViewMessageI18n(SecurityContextUtil.getLanguageCode(), SystemConstant.PARAMETERNULL));
    }
    String filename = activitifile.getOriginalFilename();
    try {
      ZipInputStream inputStream = new ZipInputStream(activitifile.getInputStream());
      Deployment deployment = this.evunProcessEngine.deployProcess(inputStream, filename);
      String isModel = request.getParameter("ismodel");
      if ((!StringUtils.isBlank(isModel)) && ("1".equals(isModel))) {
        this.evunProcessEngine.convertProcessDefinitionToModel(deployment.getId(), deployment.getCategory());
      }
     /* List<ProcessDefinition> list = this.evunProcessEngine.getProcessDefinitionByDmentId(deployment.getId());

      for (ProcessDefinition processDefinition : list) {
        exportDiagramToFile(processDefinition);
      }*/
    } catch (Exception e) {
      LOGGER.error("{}", e);

      return navTabAjaxError();
    }
    return ajaxDone(null);
  }

  @RequestMapping("processlist")
  public String processList(Model model, ProcessDefinitionCondition condition) {
    condition.setTenantId(this.getSiteCode());
    List<ProcessDefinition> pds = evunProcessEngine.getProcessDefinitionList(condition, true);
    long count = evunProcessEngine.getProcessDefinitionsCount(condition, true);
    condition.setData(pds);
    condition.setTotalCount(count);
    model.addAttribute("page", condition);
    return "engine/processDefinition_list";
  }

  @RequestMapping({ "getProcessDetail" })
  public String getProcessDetail(Model model, String id) {
    if (StringUtils.isBlank(id)) {
      model.addAttribute("message", "参数传递出错，流程id为空！");
    }
    /* ProcessDefinition pd = this.evunProcessEngine.getProcessDefinitionById(id);
     Deployment deploy = this.evunProcessEngine.getDeployMentById(pd.getDeploymentId());
     model.addAttribute("processDefinition", pd);
     model.addAttribute("deployment", deploy);
     InputStream definitionStream = this.evunProcessEngine.getProcessDefinitionImg(
       pd.getDeploymentId(), pd.getResourceName());
     XMLInputFactory xif = XMLInputFactory.newInstance();
     try {
       XMLStreamReader xtr = xif.createXMLStreamReader(definitionStream);
       BpmnModel bpmnModel = new BpmnXMLConverter()
         .convertToBpmnModel(xtr);
       if (bpmnModel.getFlowLocationMap().size() > 0) {
         model.addAttribute("isBpmnModel", Integer.valueOf(1));
         model.addAttribute("imgurl", "diagram-viewer/index.html?processDefinitionId=" + pd.getId());
       } else {
         model.addAttribute("isBpmnModel", Integer.valueOf(0));
         model.addAttribute("imgurl", "engine/processImg.htm?id=" + pd.getDeploymentId() + 
           "&resourceName=" + pd.getDiagramResourceName());
       }
     } catch (XMLStreamException e) {
       LOGGER.error("{}", e);
     }*/
    return "engine/processDetail";
  }

  @RequestMapping(value = "showProcessImg")
  public String showProcessImg(String processDefinitionId, Model model) {
    if (!StringUtils.isBlank(processDefinitionId)) {
      ProcessDefinition pd = this.evunProcessEngine.getProcessDefinitionById(processDefinitionId);
      GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd(processDefinitionId);
      BpmnModel bpmnModel = managementService.executeCommand(getBpmnModelCmd);

      Map<String, GraphicInfo> graphicInfoMap = bpmnModel.getLocationMap();

      Point point = CustomProcessDiagramGenerator.getMinXAndMinY(bpmnModel);

      int minX = point.x;
      int minY = point.y;
      minX = minX <= 5 ? 5 : minX;
      minY = minY <= 5 ? 5 : minY;
      minX -= 5;
      minY -= 5;

      List<NodeDTO> nodeDtos = new ArrayList<NodeDTO>();
      for (Entry<String, GraphicInfo> entry : graphicInfoMap.entrySet()) {
        String key = entry.getKey();
        GraphicInfo graphicInfo = entry.getValue();
        graphicInfo.setX(graphicInfo.getX() - minX);
        graphicInfo.setY(graphicInfo.getY() - minY);
        FlowElement flowElement = bpmnModel.getFlowElement(key);
        NodeDTO dto = convertNodeDto(graphicInfo, flowElement, key);
        nodeDtos.add(dto);
      }

      model.addAttribute("nodeDto", nodeDtos);
      model.addAttribute("deploymengId", pd.getDeploymentId());
      model.addAttribute("resourceName", pd.getDiagramResourceName());
    }
    return "engine/processDefinition_img";
  }

  private NodeDTO convertNodeDto(GraphicInfo graphicInfo, FlowElement flowElement, String id) {
    NodeDTO nodeDto = new NodeDTO();
    nodeDto.setX((int) graphicInfo.getX());
    nodeDto.setY((int) graphicInfo.getY());
    nodeDto.setWidth((int) graphicInfo.getWidth());
    nodeDto.setHeight((int) graphicInfo.getHeight());

    if (flowElement instanceof UserTask) {
      nodeDto.setType("userTask");
    }
    nodeDto.setId(id);
    nodeDto.setName(flowElement.getName());
    return nodeDto;
  }

  /**
   * <strong>Title : getProcessImg<br></strong>
   * <strong>Description : </strong>获取流程图<br> 
   * <strong>Create on : 2014-10-9上午8:21:29<br></strong>
   * <p>
   * @param id 流程id, 
   * @param resourceName 资源name
   * @param response 
   * @return 
   * @throws 
   * @author lidapeng<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人  | 修改日期  | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   * @throws IOException 
   */
  @RequestMapping({ "processImg" })
  public void getProcessImg(String deploymengId, String resourceName, HttpServletResponse response) throws IOException {

    InputStream is = this.evunProcessEngine.getProcessDefinitionImg(deploymengId, resourceName);

    response.setContentType("image/png");

    int len = 0;
    byte[] b = new byte[1024];

    while ((len = is.read(b, 0, 1024)) != -1) {
      response.getOutputStream().write(b, 0, len);
    }
  }

  /*private String exportDiagramToFile(ProcessDefinition processDefinition) throws IOException {
    String diagramResourceName = processDefinition.getDiagramResourceName();
    String key = processDefinition.getKey();
    int version = processDefinition.getVersion();
    String diagramPath = "";
    String diagramDir = "activit/" + key + "/" + version;

    if (this.ftpUtils.isExistisFile(diagramDir, diagramResourceName).booleanValue()) {
      return diagramPath;
    }

    InputStream resourceAsStream = this.evunProcessEngine.getProcessDefinitionImg(processDefinition.getId(),
        processDefinition.getDiagramResourceName());
    return this.ftpUtils.uploadInputStream(resourceAsStream, diagramDir, diagramResourceName);
  }*/
}
